﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing.Drawing2D;
using System.Drawing;
using Common.Net;
using Common.Unit;
using System.Net;
using System.IO;
using Newtonsoft.Json;
using System.Configuration;

namespace Joz.Web.Models
{
    public class HeadPhotoHelper
    {
        //face++ api_key
        static string api_key = ConfigurationManager.AppSettings["FaceApiKey"];
        //face++ api_secret
        static string api_secret = ConfigurationManager.AppSettings["FaceApiSecret"];

        /// <summary>
        /// 
        /// </summary>
        /// <param name="saveImgPath"></param>
        /// <param name="file"></param>
        /// <param name="waterMarkerPath"></param>
        /// <returns></returns>
        public CommonCmdResult HeadPhotoPSUseFacePlusPlus(byte[] bytes, string fileName, string fileExtension, string waterMarkerPath)
        {
            CommonCmdResult cr = new CommonCmdResult(false, 0, "没有找到头像文件，请重新上传！");
            try
            {
                Image waterMarkerPng = null;
                if (!string.IsNullOrWhiteSpace(waterMarkerPath))
                {
                    try { waterMarkerPng = Image.FromFile(waterMarkerPath); } catch { }
                }
                int radioR = 100;//默认100
                string json =FaceHelper.FacePlusPlusGetFaceInfo(bytes, fileName, fileExtension);
                dynamic D = JsonConvert.DeserializeObject<dynamic>(json);
                if (D.faces != null && D.faces.Count > 0)
                {
                    if (D.faces.Count > 1) return new CommonCmdResult(false, 0, "请不要上传多人合照！");
                    int w = (int)D.faces[0].face_rectangle.width;
                    int h = (int)D.faces[0].face_rectangle.height;
                    int l = (int)D.faces[0].face_rectangle.left;
                    int t = (int)D.faces[0].face_rectangle.top;
                    cr.Obj = HeadPhotoPS2(BytesToBitmap(bytes), radioR, l, t, w, h, waterMarkerPng);  //将头像作为结果返回
                    cr.Flag = true;
                    cr.State = 1;
                    //cr.Msg = "头像识别处理成功";
                    cr.Msg = D.faces[0].face_token;
                }
                if (!string.IsNullOrEmpty(D.error_message)) cr.Msg = D.error_message;
                return cr;
            }
            catch (Exception e)
            {
                return new CommonCmdResult(false, 0, "头像识别失败，请重试！");
            }
        }
       
        /// <summary>
        /// 字节转Bitmap
        /// </summary>
        /// <param name="Bytes"></param>
        /// <returns></returns>
        static Bitmap BytesToBitmap(byte[] Bytes)
        {
            MemoryStream stream = null;
            try
            {
                stream = new MemoryStream(Bytes);
                return new Bitmap((Image)new Bitmap(stream));
            }
            catch (ArgumentNullException ex)
            {
                throw ex;
            }
            catch (ArgumentException ex)
            {
                throw ex;
            }
            finally
            {
                stream.Close();
            }
        }
        /// <summary>
        /// 处理头像并返回
        /// </summary>
        /// <param name="img"></param>
        /// <param name="radioR">输出圆形头像的半径</param>
        /// <param name="left">人脸位置left</param>
        /// <param name="top">人脸位置top</param>
        /// <param name="width">人脸位置width</param>
        /// <param name="height">人脸位置height</param>
        /// <param name="waterMarker">水印Png图片</param>
        /// <returns></returns>
        static Bitmap HeadPhotoPS2(Bitmap img, int radioR, int left, int top, int width, int height, Image waterMarkerPng)
        {
            #region   防止超大
            int maxWidth = 1600;
            if (img.Width > maxWidth)
            {
                left = left * maxWidth / img.Width;
                top = top * maxWidth / img.Width;
                width = width * maxWidth / img.Width;
                height = height * maxWidth / img.Width;
                Bitmap img2 = new Bitmap(maxWidth, img.Height * maxWidth / img.Width);
                Graphics g2 = Graphics.FromImage(img2);
                g2.DrawImage(img, new Rectangle(0, 0, img2.Width, img2.Height), new Rectangle(0, 0, img.Width, img.Height), GraphicsUnit.Pixel);
                img.Dispose();
                img = img2;
                g2.Dispose();
            }
            #endregion

            double sideWeight = 0.8;
            int addLeft = 0;
            int addRight = 0;
            int addTop = 0;
            int addBottom = 0;
            if (left < width * sideWeight) addLeft = (int)(width * sideWeight - left + 1);
            if ((img.Width - left - width) < width * sideWeight) addRight = (int)(width * sideWeight) + width + left - img.Width + 1;
            if (img.Height < width + 2 * width * sideWeight)
            {
                addTop = (int)(width + 2 * width * sideWeight - img.Height) / 2 + 1;
            }
            addBottom = addTop;

            //if (addLeft == 0 && addRight == 0 && addTopOrBottom == 0) return img;
            Bitmap bmp = new Bitmap(img.Width + addLeft + addRight, img.Height + addTop + addBottom);
            Graphics g = Graphics.FromImage(bmp);
            Color whiteColor = Color.FromName("white");

            #region 部分头像有一条边缘色，尝试计算出来
            Rectangle cutRect = ImageCut(img);
            addLeft += cutRect.Left;
            addRight += (img.Width - cutRect.Left - cutRect.Width);
            addTop += cutRect.Top;
            addBottom += (img.Height - cutRect.Top - cutRect.Height);
            #endregion

            if (addLeft == 0 && addRight == 0 && addTop == 0)
            {
                bmp = (Bitmap)img.Clone();
            }
            else
            {
                //用指定的颜色填充Bitmap
                g.Clear(whiteColor);
                g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                //开始画图
                g.DrawImage(img, new Rectangle(addLeft, addTop, cutRect.Width, cutRect.Height), cutRect, GraphicsUnit.Pixel);
                #region 按边沿几个点取像素均值的方式扩展
                int[,] psL = new int[,] { { 5, 0 }, { 6, 0 }, { 7, 0 } };
                int[,] psLB = new int[,] { { 5, -2 }, { 6, -2 }, { 5, -3 }, { 6, -3 }, { 7, -3 } };
                for (int ax = addLeft - 1; ax >= 0; ax--)
                {
                    for (int ay = addTop; ay < bmp.Height - addBottom; ay++)
                    {
                        int R = 0;
                        int G = 0;
                        int B = 0;
                        int[,] ps = ay > (bmp.Height / 2) ? psLB : psL;
                        for (int i = 0; i < ps.Length / 2; i++)
                        {
                            Color c = bmp.GetPixel(ax + ps[i, 0], ay + ps[i, 1]);
                            R += c.R;
                            G += c.G;
                            B += c.B;
                        }
                        bmp.SetPixel(ax, ay, Color.FromArgb(R * 2 / ps.Length, G * 2 / ps.Length, B * 2 / ps.Length));
                    }
                }
                for (int ax = bmp.Width - addRight; ax < bmp.Width; ax++)
                {
                    for (int ay = addTop; ay < bmp.Height - addBottom; ay++)
                    {
                        int R = 0;
                        int G = 0;
                        int B = 0;
                        int[,] ps = ay > (bmp.Height / 2) ? psLB : psL;
                        for (int i = 0; i < ps.Length / 2; i++)
                        {
                            Color c = bmp.GetPixel(ax - ps[i, 0], ay + ps[i, 1]);
                            R += c.R;
                            G += c.G;
                            B += c.B;
                        }
                        bmp.SetPixel(ax, ay, Color.FromArgb(R * 2 / ps.Length, G * 2 / ps.Length, B * 2 / ps.Length));
                    }
                }
                for (int ay = addTop - 1; ay >= 0; ay--)
                {
                    for (int x = 0; x < bmp.Width; x++)
                    {
                        Color c1 = bmp.GetPixel(x, ay + 1);
                        Color c2 = bmp.GetPixel(x, ay + 2);
                        Color c3 = bmp.GetPixel(x, ay + 3);
                        bmp.SetPixel(x, ay, Color.FromArgb((c1.R + c2.R + c3.R) / 3, (c1.G + c2.G + c3.G) / 3, (c1.B + c2.B + c3.B) / 3));
                    }
                }
                for (int ay = bmp.Height - addBottom; ay < bmp.Height; ay++)
                {
                    for (int x = 0; x < bmp.Width; x++)
                    {
                        Color c1 = bmp.GetPixel(x, ay - 1);
                        Color c2 = bmp.GetPixel(x, ay - 2);
                        Color c3 = bmp.GetPixel(x, ay - 3);
                        bmp.SetPixel(x, ay, Color.FromArgb((c1.R + c2.R + c3.R) / 3, (c1.G + c2.G + c3.G) / 3, (c1.B + c2.B + c3.B) / 3));
                    }
                }
                #endregion
            }

            Bitmap bmp2 = new Bitmap(2 * radioR, 2 * radioR);
            g.Dispose();
            g = Graphics.FromImage(bmp2);
            //bmp.MakeTransparent(Color.Transparent);  //透明
            //g.Clear(myColor);
            g.InterpolationMode = InterpolationMode.HighQualityBicubic;
            g.SmoothingMode = SmoothingMode.HighQuality;
            GraphicsPath clipPath = new GraphicsPath();
            clipPath.AddEllipse(0, 0, bmp2.Width, bmp2.Height);
            g.SetClip(clipPath, CombineMode.Replace);//设为某路径区域
            Rectangle srcRect = new Rectangle(
                addLeft - cutRect.Left + left - (int)(sideWeight * width),
                Math.Max(0, (int)((addTop - cutRect.Top + top + height / 2) - width / 2 - sideWeight * width)),
                width + (int)(2 * sideWeight * width),
                width + (int)(2 * sideWeight * width));
            g.DrawImage(bmp, new Rectangle(0, 0, bmp2.Width, bmp2.Height), srcRect, GraphicsUnit.Pixel);
            #region 加水印
            if (waterMarkerPng != null)
            {
                //Image waterMarkerPng = Image.FromFile(AppRoot + "\\waterMarker.png");  //随机选择一张水印图
                //int rand = Common.Unit.RandomValue.Random_Int(0, 100);  //根据预定概率选择水印图
                //if (rand < 60) waterMarkerPng = Image.FromFile(AppRoot + "\\waterMarker.png");  //60%概率
                //else if (rand < 80) waterMarkerPng = Image.FromFile(AppRoot + "\\waterMarker2.png");  //20%概率
                //else if (rand < 80) waterMarkerPng = Image.FromFile(AppRoot + "\\waterMarker1.png");  //10%概率
                //else waterMarkerPng = Image.FromFile(AppRoot + "\\waterMarker3.png");  //10%概率
                g.DrawImage(waterMarkerPng, new Rectangle(0, 0, bmp2.Width, bmp2.Height), new Rectangle(0, 0, waterMarkerPng.Width, waterMarkerPng.Height), GraphicsUnit.Pixel);
            }
            Brush b = new SolidBrush(Color.FromArgb(20, Color.White));
            g.DrawString("Lvshibang.com", new Font("Verdana", 10, FontStyle.Italic), b, new Point(48, 170));  //水印            
            #endregion
            #region 平滑边缘
            SmoothSide(bmp2, 80); //第一遍
            SmoothSide(bmp2, 30); //第二遍
            #endregion
            #region 加底色
            g.Dispose();
            bmp.Dispose();
            bmp = new Bitmap(bmp2.Width, bmp2.Height);
            g = Graphics.FromImage(bmp);
            g.Clear(whiteColor);
            g.DrawImage(bmp2, new Rectangle(0, 0, bmp.Width, bmp.Height), new Rectangle(0, 0, bmp.Width, bmp.Height), GraphicsUnit.Pixel);
            bmp2 = (Bitmap)bmp.Clone();
            #endregion
            g.Dispose();
            bmp.Dispose();
            img.Dispose();


            //using (var ms = new MemoryStream())
            //{
            //    int level = 10;//图像质量1-100范围
            //    ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
            //    ImageCodecInfo ici = null;
            //    foreach (ImageCodecInfo codec in codecs)
            //    {
            //        if (codec.MimeType == "image/jpeg") ici = codec;
            //    }

            //    EncoderParameters ep = new EncoderParameters();
            //    ep.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)level);
            //    bmp2.Save(ms, ici, ep);
            //    return BytesToBitmap(ms.GetBuffer());
            //}
            return bmp2;
        }

        static void SmoothSide(Bitmap bmp, int alpha)
        {
            Dictionary<string, Color> points = new Dictionary<string, Color>();   //目标点
            for (int y = 0; y < bmp.Height; y++)
            {
                for (int x = bmp.Width / 2; x >= 0; x--)
                {
                    Color c = bmp.GetPixel(x, y);
                    if (c.A != 0) continue;
                    int count = 0;
                    c = TestPoint(bmp, x, y, out count);
                    if (count > 2) points.Add(x + "," + y, c);
                    break;  //只找第一个点
                }
                for (int x = bmp.Width / 2 + 1; x < bmp.Width; x++)
                {
                    Color c = bmp.GetPixel(x, y);
                    if (c.A != 0) continue;
                    int count = 0;
                    c = TestPoint(bmp, x, y, out count);
                    if (count > 2) points.Add(x + "," + y, c);
                    break;  //只找第一个点
                }
            }
            //画目标点
            foreach (string ky in points.Keys)
            {
                int x = int.Parse(ky.Split(',')[0]);
                int y = int.Parse(ky.Split(',')[1]);
                bmp.SetPixel(x, y, Color.FromArgb(alpha, points[ky]));
            }
        }
        static Color TestPoint(Bitmap bmp, int x, int y, out int count)
        {
            int r = 0;
            int g = 0;
            int b = 0;
            count = 0;
            string[] s = "-1,-1;-1,0;-1,1;0,-1;0,1;1,-1;1,0;1,1".Split(';', ',');
            for (int i = 0; i < s.Length; i = i + 2)
            {
                int xx = x + int.Parse(s[i]);
                int yy = y + int.Parse(s[i + 1]);
                if (xx >= 0 && xx < bmp.Width && yy >= 0 && yy < bmp.Height)
                {
                    Color c = bmp.GetPixel(xx, yy);
                    if (c.A == 0) continue;
                    r += c.R;
                    g += c.G;
                    b += c.B;
                    count++;
                }
            }
            if (count > 0)
            {
                r = r / count;
                g = g / count;
                b = b / count;
            }
            return Color.FromArgb(count > 0 ? 100 : 0, r, g, b);
        }

        static Rectangle ImageCut(Bitmap img)
        {
            int left = 0;
            int right = 0;
            int top = 0;
            int bottom = 0;
            for (int x = 0; x < img.Width; x++)
            {
                int kB = 0;
                int kW = 0;
                for (int y = 0; y < img.Height; y++) TestColor(img, x, y, ref kW, ref kB);
                if ((img.Height - kW) > 5 && (img.Height - kB) > 5) break;  //既不是黑色也不是白色
                left++;
            }
            for (int x = img.Width - 1; x >= 0; x--)
            {
                int kB = 0;
                int kW = 0;
                for (int y = 0; y < img.Height; y++) TestColor(img, x, y, ref kW, ref kB);
                if ((img.Height - kW) > 5 && (img.Height - kB) > 5) break;  //既不是黑色也不是白色
                right++;
            }
            for (int y = 0; y < img.Height; y++)
            {
                int kB = 0;
                int kW = 0;
                for (int x = 0; x < img.Width; x++) TestColor(img, x, y, ref kW, ref kB);
                if ((img.Width - kW) > 5 && (img.Width - kB) > 5) break;  //既不是黑色也不是白色
                top++;
            }
            for (int y = img.Height - 1; y >= 0; y--)
            {
                int kB = 0;
                int kW = 0;
                for (int x = 0; x < img.Width; x++) TestColor(img, x, y, ref kW, ref kB);
                if ((img.Width - kW) > 5 && (img.Width - kB) > 5) break;  //既不是黑色也不是白色
                bottom++;
            }
            return new Rectangle(left, top, img.Width - left - right, img.Height - top - bottom);
        }
        static void TestColor(Bitmap img, int x, int y, ref int kW, ref int kB)
        {
            Color c = img.GetPixel(x, y);
            if (((Color.White.R - c.R) + (Color.White.G - c.G) + (Color.White.B - c.B)) < 30) kW++;
            if (((c.R - Color.Black.R) + (c.G - Color.Black.G) + (c.B - Color.Black.B)) < 30) kB++;
        }
    }
}
